// 重复派发命令很复杂，每次都要调用相同的，
//  setAppState() 
//  setAppState()
//  setAppState()
//  导致了代码过多的陈累赘 所以dispatch出现了
// 但是在dispatch中无法访问到 useContext对象，所以需要使用高阶组件来实现

import React, { useContext, useEffect, useState } from 'react';
import appStore, { reducer, state, Store } from '../store';

// Connect 自动生成 Wrapper
// Connect 需要支持 mapStateToProps\mapDispatchToProps
// 如果传递了 selector 标识需要映射到props 如果没传就是全部的store
// dispatchSeletor 同理
const Connect = (mapStateToProps, mapDispatchToProps) => (Component) => {
    // 获取dispatch 方法
    const dispatch = Store.dispatch

    // 封装wrapper 
    const Wrapper = (props) => {
        const { setState } = useContext(appStore);
        const [, update] = useState({});

        useEffect(() => Store.subscribe(state => {
            // 在订阅时进行处理,如果出现了改变状态,就进行更新,否则就不更新
            // 实现了精准的控制更新
            const newData = mapStateToProps ? mapStateToProps(state) : { state }
            // 只有当前组件用到的数据改变了才会更新
            if (changed(newData, mapData)) {
                // 如果有更新
                update({})
            }
        }), [mapStateToProps]);

        // 检测更新
        const changed = (newData, oldData) => {
            let updateStatus = false
            for (const key in newData) {
                if (oldData[key] != newData[key]) {
                    updateStatus = true
                    break
                }
            }

            return updateStatus
        }

        // 如果传递了 mapStateToProps
        const mapData = mapStateToProps ? mapStateToProps(state) : { state }
        // 如果传递了 mapDispatchToProps
        const mapDispatch = mapDispatchToProps ? mapDispatchToProps(dispatch) : { dispatch }

        return <Component {...props} {...mapData} {...mapDispatch} />
    }

    // 返回Wrapper
    return Wrapper
}

export default Connect;